/**
 * \file Base.h
 * \brief Toplevel headerfile
 * \author Wouter Caarls <w.caarls@tnw.tudelft.nl> 
 *
 * \verbatim
 * Copyright (c) 2005 Wouter Caarls, Delft University of Technology
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * \endverbatim
 */

#ifndef __BASE_H_INCLUDED
#define __BASE_H_INCLUDED

#include <iostream>
#include <list>
#include <string>
#include "Type.h"
#include "PLog.h"

class Compound;
class SymbolTable;

extern PLog plog;

/** \brief %Type of reduction.
 *
 *  The result of a reduction can be used in different ways. How the result is used can
 *  influence the reduction itself, and therefore it is passed to reduce.
 */
enum Use {NotUsed,      ///< Result will be discarded.
	  AsExpression, ///< Result will be used as a Value.
	  AsCode        ///< Result will be used as code. Do not reduce CodeValues.
};

/** \brief Global options. */
typedef struct options_s
{
  int verbose;                                 ///< Verbosity.
  char *infile,                                ///< Filename of input file.
    *outfile;                                  ///< Filename of output file.
  char *strategydir;                           ///< Directory for external strategies.
  char *strategyfile;                          ///< Filename for inline strategies
  bool outputPromote;                          ///< Whether to output 'promote' specifier.
  bool outputDefinitions;                      ///< Whether to output function definitions.
  bool outputDeclarations;                     ///< Whether to output function declarations.
  std::list<std::string> suppressDeclarations; ///< %Variable declarations to suppress.
  std::list<std::string> suppressDefinitions;  ///< %Variable definitions to suppress.
  std::list<std::string> breakPoints;          ///< Functions to break on.
  std::list<std::string> outputSymbols;        ///< Symbols to output at exit.
  char *outsymfile;                            ///< File to output symbols to.
} options_t;

extern options_t options;
extern bool g_outputTentative;
extern int g_codes;

/** \brief Class encompassing everything that is part of a program text.
 *
 *  This is the superclass. Everything that can be represented as program text is a
 *  subclass of this one. Most of its functions are abstract.
 */
class Code
{
  public:
    Code(Type *_type=&Unknown, bool _known=false, bool _tentative=false) : type(_type), known(_known), tentative(_tentative), refcount(0)
    {
      g_codes++;
    }

    virtual ~Code()
    {
      g_codes--;
    };

    /** \brief Make a deep copy of this code tree. */
    virtual Code *copy() = 0;
    
    /** \brief Reduce the code tree.
     *
     * \c reduce is the principal function of the interpreter. It will try to reduce the
     * code tree to a value, but will return a partially reduced tree if that is
     * impossible. As a side effect, \p out will contain a new code tree consisting of
     * the pieces that could not be reduced. Assignments and declarations in this new
     * code tree can be marked tentative, signifying that they are not used in the
     * residual code.
     *
     * \param symbols Symbol table to use during reduction. This is not always the same
     * because we want to evaluate unknown branches in a separate environment.
     * \param out Code that couldn't be reduced.
     * \param use How the result of the reduction will be used.
     * \returns Reduced code. Control constructs will return VoidValue.
     */
    virtual Code* reduce(SymbolTable *symbols, Compound *out, Use use=NotUsed) = 0;

    /** \brief Residualize referenced variables.
     *
     * \c residualize marks all declarations and assignments that are referenced in the
     * code tree untentative. References to these statements are kept in the Value
     * objects the variables refer to.
     *
     * \param symbols SymbolTable to use. Stores the Value objects that keep the references.
     */
    virtual void residualize(SymbolTable *symbols)
    {
      plog.warning() << HDR << "using default residualize for type "
		     << typeid(*this).name() << std::endl;
    }

    /** \brief Output C code representing the code tree. */
    virtual std::string toString(int indentation=0) = 0;

    /** \brief Output ATerm representing the code tree. */
    virtual std::string toTerm() = 0;
    
    /** \brief Perform a search-and-replace on the code tree.
     * 
     * To support internal strategies, it is necessary to replace all references to
     * an argument in the strategy with the value of the argument. Also, this routine
     * handles anti-quotation by replacing escape sequences by the reduced value
     * of their argument.
     *
     * \param src Code being sought.
     * \param rplc Replacement Code.
     * \param symbols Symbol table for reduction.
     * \param out Output compound for reduction.
     * \returns New tree with all occurences of \p src replaced by \p rplc, and with
     * antiquotations resolved.
     */	
    virtual Code *replace(Code *src, Code *rplc,
			  SymbolTable *symbols, Compound *out)
    {
      return this->copy();
    }

    /** \brief Residualize break statements in a piece of code
     *
     * This doesn't pass loops, as that would residualize the wrong set of
     * breaks
     */
    virtual void residualizeBreaks(void)
    {
      return;
    }

  public:
    Type *type;  ///< Type of the code tree. Only valid <i>after</i> reduction.
    bool known,  ///< Whether the code represents a known constant.
      tentative; ///< Whether the code should be output by \c toString.
    int refcount;
};

/** \brief Subset of code constructs that return a value.
 *
 *  Expressions are the pieces of a program that return a value. This class is
 *  almost entirely abstract.
 */
class Expression : public Code
{
  public:
    Expression() : Code() {}
    Expression(Type *_type) : Code(_type) {}
    Expression(Type *_type, bool _known) : Code(_type, _known) {}

    virtual Expression *copy() = 0;

    virtual Expression* reduce(SymbolTable *symbols, Compound *out, Use use=NotUsed) = 0;

    virtual Expression *replace(Code *src, Code *rplc,
			  SymbolTable *symbols, Compound *out)
    {
      return this->copy();
    }
    
    virtual bool hasSideEffects() = 0;
};

class Stat;
class Declaration2;
class LeftExpression;

/** \brief Storage
 *
 *  Values are the storage space for constants and variables. The only difference between
 *  constant values and variable values is that the latter are kept in the SymbolTable
 *  instead of the program code, and can be associated with an assignment or declaration.
 */
class Value : public Expression
{
  public:
    typedef std::vector<Stat*>::iterator AI;
    typedef std::vector<Declaration2*>::iterator DI;
    
    Value(Type *_type, Stat *_assignment=NULL, Declaration2 *_declaration=NULL) :
      Expression(_type, true)
    {
      if (_declaration)
	adddeclaration(_declaration);

      if (_assignment)
	addassignment(_assignment);
    }

    Value(Type *_type, std::vector<Stat*> &_assignments,
	  std::vector<Declaration2*> &_declarations) :
      Expression(_type, true)
    {
      if (!_assignments.empty())
	for (AI ii=_assignments.begin(); ii != _assignments.end(); ++ii)
	  addassignment(*ii);
      
      if (!_declarations.empty())
	for (DI ii=_declarations.begin(); ii != _declarations.end(); ++ii)
	  adddeclaration(*ii);
    }
    
    virtual ~Value()
    {
      LOG(plog.crawl, HDR << "Destroying value " << this << std::endl);
    
      clearassignments();
      cleardeclarations();
    }

    virtual Value *copy() = 0;

    /** \brief Cast the object represented by the Value to an integer. */
    virtual int castToInteger() const = 0;

    /** \brief Cast the object represented by the Value to a double. */
    virtual double castToFloat() const = 0;

    virtual void residualize(SymbolTable *symbols)
    {
      residualize(symbols, false);
    }

    virtual void residualize(SymbolTable *symbols, bool markUnknown);
    
    virtual void addassignment(Stat* assignment);
    virtual void clearassignments(void);
    virtual void adddeclaration(Declaration2* declaration);
    virtual void cleardeclarations(void);

    /** \brief Remove references to the generating declarations and assignments */
    virtual void removeGenerators()
    {
      cleardeclarations();
      clearassignments();
    }

    /** \brief Mark variables unknown if they have changed.
     *
     * Merge in \c rhs 's assignments, and mark the variable unknown if there
     * were any new ones, or if rhs is unknown.
     *
     * \param symbols SymbolTable to use in case of a PointerValue.
     * \param rhs Value to compare to.
     * \param mergeAssignemnts Whether to actually merge in new assignments,
     *        or only mark unknown
     * \returns Whether assignments have been merged
     */
    virtual bool dirtyChanged(SymbolTable *symbols, Value *rhs, bool mergeAssignments=true);

    virtual Value *replace(Code *src, Code *rplc,
			  SymbolTable *symbols, Compound *out)
    {
      return this->copy();
    }

    /** \brief Check whether the object represented by this Value is known.
     *
     * A PointerValue can be known without the object pointed to by it being known.
     * This, therefore, is a <i>deep</i> version of \c known.
     * 
     * \param symbols SymbolTable to use.
     * \param out Residualized code resulting from intermediate reductions.
     * \param useValue Whether to include the \c known state of the storage itself.
     * \returns Result of the check.
     */
    virtual bool storageIsKnown(SymbolTable *symbols, Compound *out, bool useValue)
    {
/*
      if (useValue)
*/
	return known;
/*      else

	return true;
*/
    }

    bool hasSideEffects() { return false; }

    virtual void outputKnownValues(LeftExpression *base, Compound *out) = 0;

    void mergeAssignments(std::vector<Stat*> &_assignments);
    void mergeDeclarations(std::vector<Declaration2*> &_declarations);

  public:
    std::vector<Stat*> assignments; ///< Assignment statements necessary for the residualization of this Value.
    std::vector<Declaration2*> declarations; ///< Declarations necessary for the residualization of this Value.
};

class Id;

/** \brief Subset of Expressions that can be assigned to.
 *
 *  A LeftExpression is an expression that can occur at the left side of an assignment.
 *  It therefore has a number of additional member functions for manipulating the
 *  storage space that it represents. Note that, unlike most other Code subclasses,
 *  the reduce member function is implemented in the base class, and calls
 *  additional subclass member functions to perform the operation. 
 */
class LeftExpression : public Expression
{
  public:
    typedef std::list<Value**>::iterator SI;

    LeftExpression() : Expression() {}
    LeftExpression(Type *_type) : Expression(_type) {}

    virtual bool equals(const LeftExpression *rhs) const = 0;

    virtual LeftExpression *copy() = 0;

    virtual Expression *reduce(SymbolTable *symbols, Compound *out, Use use=NotUsed);

    /** \brief Residualize referenced variables.
     *
     * \c residualize marks all declarations and assignments that are referenced in the
     * code tree untentative. References to these statements are kept in the Value
     * objects the variables refer to.
     *
     * When residualizing a LeftExpression, \c residualize is recursively called for
     * all its possible storage locations, but not for the storage path(s). Only their
     * declarations and assignments are residualize, to avoid residualizing all elements
     * of an array when a single one is residualized. The indexing expressions are
     * handled by \c residualizeStoragePath.
     *
     * \param symbols SymbolTable to use. Stores the Value objects that keep the references.
     */
    virtual void residualize(SymbolTable *symbols);

    /** \brief Set the storage pointed to by this LeftExpression to \p newdata.
     *
     * %If it points to more than one possible storage location, they are cleared instead.
     * 
     * \param symbols SymbolTable to use.
     * \param out Residualized code resulting from intermediate reductions.
     * \param newdata Data to put into storage.
     */
    virtual void setData(SymbolTable *symbols, Compound *out, Value *newdata);

    /** \brief Clears the storage pointed to by this LeftExpression.
     *
     * %If the data that has to be put into a storage location is unknown, it
     * is cleared, and all further references to it are residualized. This function
     * does the clearing.
     *
     * \param symbols SymbolTable to use.
     * \param out Residualized code resulting from intermediate reductions.
     */
    virtual void clearData(SymbolTable *symbols, Compound *out);

    virtual Expression *replace(Code *src, Code *rplc,
			  SymbolTable *symbols, Compound *out)
    {
      return this->copy();
    }

    /** \brief Find the storage pointed to by this LeftExpression.
     *
     * This function works by first recursively finding the storage pointed to by
     * its child, and then applying itself to all found locations, yielding the output.
     *
     * \param symbols SymbolTable to use.
     * \param out Residualized code resulting from intermediate reductions.
     * \param storage List containing the possible storage locations (output parameter).
     * \param path List containing the storage locations, as well as the locations
     *        leading up to them. For example, the indexed element along with the array
     *        itself, or a dereferenced value along with the pointer to it.
     */
    virtual void findStorage(SymbolTable *symbols, Compound *out,
			     std::list<Value**> &storage, std::list<Value**> &path) = 0;

    /** \brief Build the storage path from this LeftExpression.
     *
     * This comes down to reducing any indexing expressions. \c buildStoragePath also
     * acts as the LeftExpresion's \c reduce in the sense that it sets the types.
     *
     * \param symbols SymbolTable to use.
     * \param out Residualized code resulting from intermediate reductions.
     */   
    virtual LeftExpression* buildStoragePath(SymbolTable *symbols, Compound *out) = 0;
    
    /** \brief Residualize expressions in a storage path.
     *
     * Calls \c residualize for all indexing expressions in the storage path.
     *
     * \param symbols SymbolTable to use.
     */
    virtual void residualizeStoragePath(SymbolTable *symbols) = 0;

    /** \brief Remove variable references from a storage path.
     *
     * In order to use a storage path outside of its current scope, it must not
     * reference any variables by name. \c anonimizeStoragePath replaces the
     * reference to the "base" variable by an IndexedSymbol, and replaces all
     * unknown indexing expressions by a wildcard.
     *
     * \param tindex Index of the base variable in a SymbolTable.
     * \returns Anonimized storage path.
     */
    virtual LeftExpression* anonimizeStoragePath(int tindex) = 0;

    /** \brief Find the base identifier in this LeftExpression.
     *
     * The base identifier is the \c a in
     * \code (*a[b.q]).x \endcode
     *
     * \param symbols SymbolTable to use.
     * \returns Base identifier.
     */
    virtual Id *findId(SymbolTable *symbols) = 0;

    virtual bool hasSideEffects() = 0;
};

/** \brief Set last statement encountered by \em reduce. */
void setLastStatement(Code *code);

/** \brief Bail with an error message (user interface). */
#define error(msg) _error(__FILE__, __LINE__, __PRETTY_FUNCTION__, msg)

/** \brief Bail with an error message (back end). */
void _error(const char *file, const int line, const char *function, const char *msg);

/** \brief Output \p separator \p indentation times, for pretty-printing. */
std::string indent(int indentation, char *separator="  ");

/** \brief Open a pipe to an external \p command.
 *
 * \param command Command to execute (no arguments are allowed).
 * \param filedes two file descriptors. \p filedes[0] is for reading, \p filedes[1]
 *        for writing.
 * \returns 0 if successful, and an errorcode otherwise.
 */
int popen2(const char *command, int *filedes);

/** \brief Open a pipe to an external \p command, with arguments.
 *
 * \param command Command to execute.
 * \param args Arguments to pass to command. Separated by spaces.
 * \param filedes two file descriptors. \p filedes[0] is for reading, \p filedes[1]
 *        for writing.
 * \returns 0 if successful, and an errorcode otherwise.
 */int popen2a(const char *command, char *args, int *filedes);

int fileCompare(char *name1, char *name2);
int fileDateCompare(char *name1, char *name2);

Id *DecodeId(Code *did, SymbolTable *symbols, Compound *out);

#endif /* __BASE_H_INCLUDED */
